package com.tencent.qf.common.util;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import java.util.Map;
import java.util.TreeMap;

@Slf4j
public class SignatureUtils {
    private static final String MAC_NAME = "HmacSHA1";
    private static final String ENCODING = "UTF-8";

    public static String sign(Object request, String appSecret) {
        String jsonBody = JSON.toJSONString(request);
        // ascii排序、拼接
        TreeMap<String, Object> treeMap = JSON.parseObject(jsonBody, new TypeReference<TreeMap<String, Object>>() {
        });
        StringBuilder waitEncrypted = new StringBuilder();
        for (Map.Entry<String, Object> entry : treeMap.entrySet()) {
            Object value = entry.getValue();
            if (value == null) {
                continue;
            }
            if (ObjectUtil.isBasicType(value) || value instanceof String) {
                waitEncrypted.append(value);
            } else if (value instanceof JSONObject){
                TreeMap<String, Object> innerTreeMap = new TreeMap<>();
                innerTreeMap.putAll((JSONObject)value);
                waitEncrypted.append(JSON.toJSONString(innerTreeMap));
            }else {
                waitEncrypted.append(JSON.toJSONString(value));
            }
        }
        waitEncrypted.append(appSecret);

        try {
            SecretKeySpec signingKey = new SecretKeySpec(appSecret.getBytes(ENCODING), MAC_NAME);
            // get an hmac_sha1 Mac instance and initialize with the signing key
            Mac mac = Mac.getInstance(MAC_NAME);
            mac.init(signingKey);
            // compute the hmac on input data bytes
            byte[] rawHmac = mac.doFinal(waitEncrypted.toString().getBytes(ENCODING));
            return base64Encode(rawHmac);
        } catch (InvalidKeyException e) {
            log.info("签名入参，jsonBody：{}", jsonBody);
            log.error("签名失败：", e);
        } catch (UnsupportedEncodingException e) {
            log.info("签名入参，jsonBody：{}", jsonBody);
            log.error("签名失败：", e);
        } catch (NoSuchAlgorithmException e) {
            log.info("签名入参，jsonBody：{}", jsonBody);
            log.error("签名失败：", e);
        }
        return null;
    }

    private static String base64Encode(byte[] key) {
        final Base64.Encoder encoder = Base64.getEncoder();
        return encoder.encodeToString(key);
    }
}
